package com.meilingcloud.biobank.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.meilingcloud.biobank.domain.SampleAlarm;
import com.meilingcloud.biobank.domain.SampleBackup;
import com.meilingcloud.biobank.domain.SampleType;
import com.meilingcloud.biobank.mapper.SampleAlarmMapper;
import com.meilingcloud.biobank.service.ISampleAlarmService;
import com.meilingcloud.biobank.service.ISampleBackupService;
import com.meilingcloud.biobank.service.ISampleTypeService;
import com.meilingcloud.common.enums.SampAlarmType;
import com.meilingcloud.common.enums.SampStatue;
import com.meilingcloud.common.utils.DateUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 样本预警 Service业务层处理
 *
 * @author chenl
 * @date 2021-05-26
 */
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Service
public class SampleAlarmServiceImpl extends ServiceImpl<SampleAlarmMapper, SampleAlarm> implements ISampleAlarmService {

    private final ISampleBackupService sampleBackupService;
    private final ISampleTypeService sampleTypeService;

    @Override
    public List<SampleAlarm> queryList(SampleAlarm sampleAlarm) {
        LambdaQueryWrapper<SampleAlarm> lqw = Wrappers.lambdaQuery();
        if (sampleAlarm.getSampBackupId() != null) {
            lqw.eq(SampleAlarm::getSampBackupId, sampleAlarm.getSampBackupId());
        }
        if (sampleAlarm.getSampTypeId() != null) {
            lqw.eq(SampleAlarm::getSampTypeId, sampleAlarm.getSampTypeId());
        }
        if (StringUtils.isNotBlank(sampleAlarm.getSampAlarmType())) {
            lqw.eq(SampleAlarm::getSampAlarmType, sampleAlarm.getSampAlarmType());
        }
        return this.list(lqw);
    }

    @Override
    public Integer getAlarmCount() {
        return this.count();
    }

    @Override
    public List<SampleAlarm> handleResults(List<SampleAlarm> sampleAlarms) {
        List<Long> sampBackupIds = sampleAlarms.stream().map(SampleAlarm::getSampBackupId).collect(Collectors.toList());
        List<Long> sampTypeIds = sampleAlarms.stream().map(SampleAlarm::getSampTypeId).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(sampBackupIds) || CollectionUtil.isEmpty(sampTypeIds)) {
            return sampleAlarms;
        }
        List<SampleBackup> sampleBackupList = sampleBackupService.listByIds(sampBackupIds);
        List<SampleBackup> sampleBackups = sampleBackupService.handleResult(sampleBackupList);
        List<SampleType> sampleTypes = sampleTypeService.listByIds(sampTypeIds);
        sampleAlarms.forEach(alarm -> {
            sampleBackups.forEach(b -> {
                if (ObjectUtil.equal(alarm.getSampBackupId(), b.getSampBackupId())) {
                    alarm.setSampBackupCode(b.getSampBackupCode());
                    alarm.setSampSourceName(b.getSampSourceName());
                    alarm.setSampTypeName(b.getSampTypeName());
                    alarm.setSampState(b.getSampState());
                    alarm.setSampLocation(b.getSampLocation());
                    alarm.setSampFreezeThawCount(b.getSampFreezeThawCount());
                    alarm.setQrCode(b.getQrCode());
                    alarm.setSamplingTime(b.getSamplingTime());
                }
            });
            sampleTypes.forEach(t -> {
                if (ObjectUtil.equal(alarm.getSampTypeId(), t.getSampTypeId())) {
                    alarm.setSampTypeShelfLife(t.getSampTypeShelfLife());
                    alarm.setSampTypeLowUseYear(t.getSampTypeLowUseYear());
                }
            });
        });
        return sampleAlarms;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void calculateAlarm(Integer expireGap) {
        // 1.获取所有样本类型
        List<SampleType> sampleTypes = sampleTypeService.list();
        if (CollectionUtil.isEmpty(sampleTypes)) {
            return;
        }
        // 2.根据样本保质天数和使用年限筛选样本
        Date nowDate = DateUtils.getNowDate();
        List<SampleAlarm> sampleAlarmList = new ArrayList<>();
        sampleTypes.forEach(item -> {
            if (ObjectUtil.isEmpty(item.getSampTypeShelfLife())) {
                return;
            }
            Date guaranteeDate = DateUtils.subDateByDay(nowDate, item.getSampTypeShelfLife());
            Date preGuaranteeDate = DateUtils.addDateByDay(guaranteeDate, expireGap);
            // 即将过期
            List<SampleBackup> sampleBackups = sampleBackupService.list(new LambdaQueryWrapper<SampleBackup>()
                    .eq(SampleBackup::getSampTypeId, item.getSampTypeId())
                    .between(SampleBackup::getSamplingTime, guaranteeDate, preGuaranteeDate)
                    .and(wrapper -> wrapper.eq(SampleBackup::getSampState, SampStatue.NORMAL.getCode())
                            .or()
                            .eq(SampleBackup::getSampState, SampStatue.TO_CLAIM.getCode())
                            .or()
                            .eq(SampleBackup::getSampState, SampStatue.TO_OUT.getCode())
                            .or()
                            .eq(SampleBackup::getSampState, SampStatue.TO_DESTROY.getCode())));
            List<SampleAlarm> willExpireList = sampleBackups.stream().map(b -> {
                SampleAlarm sampleAlarm = new SampleAlarm();
                sampleAlarm.setSampBackupId(b.getSampBackupId());
                sampleAlarm.setSampTypeId(item.getSampTypeId());
                sampleAlarm.setSampAlarmType(SampAlarmType.WILL_EXPIRE.getCode());
                return sampleAlarm;
            }).collect(Collectors.toList());
            sampleAlarmList.addAll(willExpireList);

            // 已过期
            List<SampleBackup> sampleBackupList = sampleBackupService.list(new LambdaQueryWrapper<SampleBackup>()
                    .eq(SampleBackup::getSampTypeId, item.getSampTypeId())
                    .lt(SampleBackup::getSamplingTime, guaranteeDate)
                    .and(wrapper -> wrapper.eq(SampleBackup::getSampState, SampStatue.NORMAL.getCode())
                            .or()
                            .eq(SampleBackup::getSampState, SampStatue.TO_CLAIM.getCode())
                            .or()
                            .eq(SampleBackup::getSampState, SampStatue.TO_OUT.getCode())
                            .or()
                            .eq(SampleBackup::getSampState, SampStatue.TO_DESTROY.getCode())));
            List<SampleAlarm> expiredList = sampleBackupList.stream().map(s -> {
                SampleAlarm sampleAlarm = new SampleAlarm();
                sampleAlarm.setSampBackupId(s.getSampBackupId());
                sampleAlarm.setSampTypeId(item.getSampTypeId());
                sampleAlarm.setSampAlarmType(SampAlarmType.EXPIRED.getCode());
                return sampleAlarm;
            }).collect(Collectors.toList());
            sampleAlarmList.addAll(expiredList);
        });
        // 3.删除表中数据 重新插入数据
        this.remove(new LambdaQueryWrapper<SampleAlarm>().gt(SampleAlarm::getSampAlarmId, 0).and(
                wrapper -> wrapper.eq(SampleAlarm::getSampAlarmType, SampAlarmType.EXPIRED.getCode())
                        .or()
                        .eq(SampleAlarm::getSampAlarmType, SampAlarmType.WILL_EXPIRE.getCode())));
        this.saveBatch(sampleAlarmList);
    }

    @Override
    public void freezeThawAlarm(Integer count) {
        List<SampleBackup> sampleBackups = sampleBackupService.list(new LambdaQueryWrapper<SampleBackup>()
                .gt(SampleBackup::getSampFreezeThawCount, count)
                .and(wrapper -> wrapper.eq(SampleBackup::getSampState, SampStatue.NORMAL.getCode())
                        .or()
                        .eq(SampleBackup::getSampState, SampStatue.TO_CLAIM.getCode())
                        .or()
                        .eq(SampleBackup::getSampState, SampStatue.TO_OUT.getCode())
                        .or()
                        .eq(SampleBackup::getSampState, SampStatue.TO_DESTROY.getCode())));
        List<SampleAlarm> freezeThawList = sampleBackups.stream().map(b -> {
            SampleAlarm sampleAlarm = new SampleAlarm();
            sampleAlarm.setSampBackupId(b.getSampBackupId());
            sampleAlarm.setSampTypeId(b.getSampTypeId());
            sampleAlarm.setSampAlarmType(SampAlarmType.FREEZER_THAW.getCode());
            return sampleAlarm;
        }).collect(Collectors.toList());
        // 删除表中数据 重新插入数据
        this.remove(new LambdaQueryWrapper<SampleAlarm>().gt(SampleAlarm::getSampAlarmId, 0)
                .eq(SampleAlarm::getSampAlarmType, SampAlarmType.FREEZER_THAW.getCode()));
        this.saveBatch(freezeThawList);
    }

}
